package com.dyx.source.reactor.singleThreadReactor;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * 最基本的单Reactor单线程模型
 * 作用：Reactor线程，负责多路分离套接字，有新连接到来触发connect事件时，负责响应事件，将事件分发给绑定了该事件的 Handler 处理
 *
 * @author dengyouxu
 * @date 2021.06.22 10:14:57:601
 *
 * 缺点：
 * 这整个reactor线程中，需要执行处理所有的 accept、read、decode、process、encode、send 事件，处理成百上千的链路时性能上无法支撑；
 *
 * 一旦 reactor 线程意外跑飞或者进入死循环，会导致整个系统通信模块不可用。
 *
 * 当 NIO 线程负载过重之后，处理速度将变慢，这会导致大量客户端连接超时，超时之后往往会进行重发，这更加重了 NIO 线程的负载，最终会导致大量消息积压和处理超时，成为系统的性能瓶颈；
 *
 */
public class Reactor implements Runnable {

    // 三要素都要是类变量   selector--channnel--buffer(读写才要buffer,连接不需要buffer)
    final Selector selector;
    final ServerSocketChannel serverSocketChannel;

    /**
     *
     // 初始五句话：初始化selector  初始化服务端channel 服务端channel绑定端口  服务端channel设置为非阻塞  服务端channel注册到selector上面，返回在selector中表示这个服务端channel的key
     // 最后一句：服务端这个channel去绑定一个服务端acceptor对象，用来接收请求的，参数为服务端channel和服务端selector
     * @param port
     * @throws IOException
     */
    public Reactor(int port) throws IOException { //Reactor初始化
        // 初始化selector
        selector = Selector.open();
        // 只有一个serverSocketChannel
        serverSocketChannel = ServerSocketChannel.open();
        //在ServerSocketChannel绑定监听端口
        serverSocketChannel.socket().bind(new InetSocketAddress(port));
        //设置ServerSocketChannel为非阻塞
        serverSocketChannel.configureBlocking(false);

        //分步处理,第一步,接收accept事件
        // ServerSocketChannel向selector注册一个OP_ACCEPT事件，然后返回该通道的key     SelectionKey.OP_ACCEPT  16
        SelectionKey sk = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        //给定key一个附件的Acceptor对象
        sk.attach(new Acceptor(selector, serverSocketChannel));
    }

    public void run() {
        try {
            // Reactor 就是一个执行 while (true) { selector.select(); …} 循环的线程，会源源不断的产生新的事件，称作反应堆很贴切。
            //在线程被中断前持续运行
            while (!Thread.interrupted()) {
                //若没有事件就绪则不往下执行，NIO的底层是linux非阻塞io,轮询
                selector.select();
                //取得所有已就绪事件的key集合
                Set<SelectionKey> selected = selector.selectedKeys();
                // 迭代iterator() while
                Iterator<SelectionKey> it = selected.iterator();
                while (it.hasNext()) {
                    //Reactor负责dispatch收到的事件，
                    //根据事件的key进行分发调度
                    dispatch(it.next());
                }
                selected.clear();
            }
        } catch (IOException ex) { /* ... */ }
    }

    void dispatch(SelectionKey k) {
        Runnable r = (Runnable) (k.attachment());
        //调用之前注册的callback对象
        if (r != null) {
            // 这里注意是直接调用的是run方法，并没有开启线程
            r.run();
        }
    }


}